package io.github.fb513.common.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;

public class JsonParser {

    private final ObjectMapper objectMapper;

    public JsonParser(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        // 配置忽略未知属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public <T> T parseJsonToObj(String jsonStr, Class<T> clazz) {
        try {
            return objectMapper.readerFor(clazz).readValue(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public <T> T parseJsonToObj(String jsonStr, TypeReference<T> type) {
        try {
            return objectMapper.readValue(jsonStr, type);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public <T> List<T> parseJsonToList(String jsonStr, Class<T> clazz) {
        try {
            return objectMapper.readerForListOf(clazz).readValue(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public JsonNode parseJsonToJsonNode(String jsonStr) {
        try {
            return objectMapper.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public String formatObjToJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(e);
        }
    }

    public <T> T convertToPojo(JsonNode jsonNode, Class<T> clazz) {
        try {
            return objectMapper.treeToValue(jsonNode, clazz);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(e);
        }
    }

    public <T> T convertToPojo(JsonNode jsonNode, Class<T> clazz, Class<?>... types) {
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(clazz, types);
            return objectMapper.treeToValue(jsonNode, javaType);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(e);
        }
    }

    private static class JsonParseException extends RuntimeException {

        public JsonParseException(String msg) {
            super(msg);
        }

        public JsonParseException(String msg, Throwable cause) {
            super(msg, cause);
        }

        public JsonParseException(Throwable cause) {
            super(cause);
        }
    }
}
